package com.zmn.oms.business.impl.log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.base.engineer.dubbo.interfaces.engineer.cooperate.EngineerCooperateInfoListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.Option;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.mcc.common.dto.staff.StaffDRO;
import com.zmn.mcc.dubbo.interfaces.staff.StaffListRemoteService;
import com.zmn.oms.business.interfaces.conf.distributereason.ConfOrderDistributeReasonBService;
import com.zmn.oms.business.interfaces.log.OrderRedistributeLogBService;
import com.zmn.oms.common.constant.ConfRedistributeConsts;
import com.zmn.oms.common.constant.MessageQueueTagConsts;
import com.zmn.oms.common.constant.OrderWorkRedistributeLogConsts;
import com.zmn.oms.common.dro.redistribute.RedistributeMsgDRO;
import com.zmn.oms.common.dto.OmsBaseOperator;
import com.zmn.oms.common.dto.OrderWorkRedistributeOperator;
import com.zmn.oms.manager.utils.OmsMqTagConsts;
import com.zmn.oms.model.bo.conf.distribute.reason.ConfOrderDistributeReasonBO;
import com.zmn.oms.model.dto.log.OrderRedistributeLogQuery;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.log.OrderRedistributeLog;
import com.zmn.oms.model.entity.redistribute.OrderWorkRedistributeApply;
import com.zmn.oms.model.entity.redistribute.OrderWorkRedistributeInfo;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.redistribute.OrderWorkRedistributeInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author sunlife
 * @date:2022/5/13 下午7:24
 * description:
 */
@Slf4j
@Service
public class OrderRedistributeLogBServiceImpl implements OrderRedistributeLogBService {

    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    private OrderWorkRedistributeInfoService orderWorkRedistributeInfoService;
    @Autowired
    private ConfOrderDistributeReasonBService confOrderDistributeReasonBService;
    @Autowired
    private ZmnMQSender zmnMQSender;

    @DubboReference(version = com.zmn.mcc.dubbo.dto.DubboConsts.INTERFACE_VERSION)
    private StaffListRemoteService staffListRemoteService;
    @DubboReference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    private EngineerCooperateInfoListRemoteService engineerCooperateInfoListRemoteService;

    @Value("${spring.mq.topic.performance:''}")
    private String performanceTopic;


    @Override
    public List<OrderRedistributeLog> findOrderLogsByWorkId(Long workId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("workId").is(workId);
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
	    List<OrderRedistributeLog> redistributeLogList = mongoTemplate.find(query, OrderRedistributeLog.class);
	    if (CollectionUtils.isNotEmpty(redistributeLogList)) {
		    redistributeLogList.forEach(redistributeLog -> {
			    redistributeLog.setType(OrderWorkRedistributeLogConsts.ORDER_LOG_TYPE_REDISTRIBUTE);
		    });
	    }
        return redistributeLogList;
    }

    @Override
    public List<OrderRedistributeLog> findOrderLogsByQuery(OrderRedistributeLogQuery orderLogQuery) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("redistributeId").is(orderLogQuery.getRedistributeId());
        if (NumberUtil.isNotNullOrZero(orderLogQuery.getOperatorId())) {
            criteria.and("operatorId").is((long) orderLogQuery.getOperatorId());
        }
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderRedistributeLog.class);
    }

    @Override
    public void save(OrderRedistributeLog log) {
        if (log.getCreateTime() == null) {
            log.setCreateTime(new Date());
        }

        if (StringUtils.isBlank(log.getOperatorTypeName()) && log.getOperatorType() != null) {
            log.setOperatorTypeName(GlobalConsts.getOperatorTypeName(log.getOperatorType()));
        }

        mongoTemplate.save(log);
    }

    @Override
    public void nodeNotice(OrderRedistributeLog orderLog, OrderWorkRedistributeApply orderWorkRedistributeApply) {
        log.debug("日志参数：{}，推送参数：{}", JSON.toJSONString(orderLog), JSON.toJSONString(orderWorkRedistributeApply));
        RedistributeMsgDRO msgDRO = BeanMapper.map(orderWorkRedistributeApply, RedistributeMsgDRO.class);
        ConfOrderDistributeReasonBO reasonBO = confOrderDistributeReasonBService.getConfOrderDistributeReasonById(orderWorkRedistributeApply.getReasonId());
        OrderWorkRedistributeInfo orderWorkRedistributeInfo = orderWorkRedistributeInfoService.findRedistributeInfoById(orderWorkRedistributeApply.getRedistributeId());
        msgDRO.setMasterId(orderWorkRedistributeInfo.getMasterId().intValue());
        msgDRO.setCountEnable(reasonBO.getCountEnable());
        switch (orderLog.getType()) {
            case OrderWorkRedistributeLogConsts.ORDER_REDISTRIBUTE_LOG_TYPE_ADD_APPLY:
                if (!Objects.equals(orderWorkRedistributeApply.getHelpType(), ConfRedistributeConsts.HELP_TYPE_NONE)) {
                    // 需要发起求助 通知预警系统
                    msgDRO.setBizType(1);
                    this.sendMessage(msgDRO);
                    return;
                }
                return;
            case OrderWorkRedistributeLogConsts.ORDER_REDISTRIBUTE_LOG_TYPE_START_AUDIT:
                // 开始审核
                msgDRO.setBizType(3);
                this.sendMessage(msgDRO);
                return;
            case OrderWorkRedistributeLogConsts.ORDER_REDISTRIBUTE_LOG_TYPE_AUDIT:
                // 审核操作
                msgDRO.setBizType(4);
                this.sendMessage(msgDRO);
                return;
            case OrderWorkRedistributeLogConsts.ORDER_REDISTRIBUTE_LOG_TYPE_HELP_TAKE:
                // 求助领单
                msgDRO.setBizType(2);
                this.sendMessage(msgDRO);
                return;
            case OrderWorkRedistributeLogConsts.ORDER_REDISTRIBUTE_LOG_TYPE_CANCEL:
                msgDRO.setBizType(6);
                this.sendMessage(msgDRO);
                return;
            default:
                return;
        }
    }

    @Override
    public void noticeCancelRedistribute(OrderLog orderLog, OrderWork dbOrderWork, OmsBaseOperator omsBaseOperator, Object proceed) {
        // 延迟三秒执行 防止未提交事物 or 同步到es
        long time = System.currentTimeMillis() + 3000;
        String key = String.format("redistribute-cancel-%s-%s", dbOrderWork.getOrderId(), orderLog.getType());
        JSONObject jb = new JSONObject();
        jb.put("orderId", dbOrderWork.getOrderId());
        jb.put("workId", dbOrderWork.getWorkId());
        jb.put("type", orderLog.getType());
        String content = jb.toJSONString();
        log.info("发送改派申请取消消息：tag:{},key:{},message:{}", OmsMqTagConsts.ORDER_WORK_REDISTRIBUTE_CANCEL_TAG, key, content);
        zmnMQSender.sendWithStartDeliverTime(MqTopicConsts.ZMN_TOPIC_OMS, OmsMqTagConsts.ORDER_WORK_REDISTRIBUTE_CANCEL_TAG, key, content, time);

    }

    @Override
    public void notice(OrderRedistributeLog orderLog, OrderWorkRedistributeOperator operator, OrderWorkRedistributeApply orderWorkRedistributeApply) {
        String key = String.format("%s-%s", orderWorkRedistributeApply.getRedistributeId(), orderLog.getType());
        RedistributeMsgDRO msgDRO = new RedistributeMsgDRO();
        msgDRO.setRedistributeId(orderWorkRedistributeApply.getRedistributeId());
        msgDRO.setOrderId(orderLog.getOrderId());
        msgDRO.setWorkId(orderLog.getWorkId());
        msgDRO.setNodeType(orderLog.getType());
        msgDRO.setOperatorId(operator.getOperatorId());
        msgDRO.setOperator(operator.getOperator());
        msgDRO.setOperatorType(operator.getOperatorType());
        log.info("改派节点通知：tag:{},key:{},message:{}", MessageQueueTagConsts.ORDER_WORK_REDISTRIBUTE_TAG, key, JSON.toJSONString(msgDRO));
        zmnMQSender.send(MqTopicConsts.ZMN_TOPIC_OMS, MessageQueueTagConsts.ORDER_WORK_REDISTRIBUTE_TAG, key, JSON.toJSONString(msgDRO));
    }

    /**
     * 处理订单 log 员工数据
     *
     * @param baseLogList
     */
    @Override
    public void processLogStaffDept(List<OrderRedistributeLog> baseLogList) {
        if (CollectionUtils.isEmpty(baseLogList)) {
            return;
        }

        Map<Integer, String> staffDeptMap = null;

        // 员工Id集合
        List<Integer> staffIds = baseLogList.stream().filter(e -> e.getOperatorId() < Integer.MAX_VALUE && (
                Objects.equals(e.getOperatorType(), com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_STAFF) || Objects
                        .equals(e.getOperatorType(), com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_MASTER)))
                .map(e -> e.getOperatorId().intValue()).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(staffIds)) {
            // 员工集合组装部门数据
            ResponseDTO<List<StaffDRO>> staffList = staffListRemoteService.listStaffByStaffIds(staffIds, null);
            List<StaffDRO> staffListData = staffList.getData();
            if (CollectionUtils.isNotEmpty(staffListData)) {
                staffList.getData().forEach(e -> e.setDeptName(StringUtils.defaultString(e.getDeptName())));
                // 拼装员工部门
                staffDeptMap = staffList.getData().stream().collect(Collectors.toMap(StaffDRO::getStaffId, StaffDRO::getDeptName));
            }
        }


        Map<Integer, String> finalStaffDeptMap = staffDeptMap;
        baseLogList.forEach(e -> {
            if (finalStaffDeptMap != null && finalStaffDeptMap.containsKey(e.getOperatorId().intValue())) {
                String deptName = finalStaffDeptMap.get(e.getOperatorId().intValue());
                if (StringUtil.isNotBlank(e.getOperator())) {
                    e.setOperator(deptName + "-" + e.getOperator());
                } else {
                    e.setOperator(deptName);
                }
            }
            // 日志格式
            switch (e.getOperatorType()) {
                case com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_MASTER:
                    e.setOperator(e.getOperator() + "（工程师）");
                    break;
                case com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_STAFF:
                    e.setOperator(e.getOperator() + "（员工）");
                    break;
                case com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_USER:
                    e.setOperator(e.getOperator() + "（用户）");
                    break;
                default:
                    break;
            }
        });
    }

    /**
     * 处理订单log 工程师数据
     * @param baseLogList
     * @param bizType
     */
    @Override
    public void processOrderLogMaster(List<OrderRedistributeLog> baseLogList, Integer bizType) {

        if (CollectionUtils.isEmpty(baseLogList)) {
            return;
        }

        // 工程师Id集合
        List<Integer> masterIds = baseLogList.stream().filter(e -> e.getOperatorId() < Integer.MAX_VALUE && Objects
                .equals(e.getOperatorType(), com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_MASTER))
                .map(e -> e.getOperatorId().intValue()).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(masterIds)) {
            return;
        }

        // 处理工程师 分组数据
        baseLogList.forEach(e -> {
            if (!Objects.equals(e.getOperatorType(), com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_MASTER)){
                return;
            }

            try {
                ResponseDTO<Option<Integer>> responseDTO = engineerCooperateInfoListRemoteService.getProductGroupByEngineerIdAndBizType(
                        e.getOperatorId().intValue(), bizType);

                if (responseDTO.isSuccess() && Objects.nonNull(responseDTO.getData())) {
                    String masterSkillGroupName = responseDTO.getData().getLabel();
                    if (StringUtil.isNotBlank(masterSkillGroupName)) {
                        e.setOperator(StringUtils.defaultString(masterSkillGroupName) + "-" + e.getOperator());
                    }
                }
            } catch (Exception ex) {
            }

        });
    }

    /**
     * 发送消息
     *
     * @param msgDRO
     */
    private void sendMessage(RedistributeMsgDRO msgDRO) {
        String key = String.format("%s-%s", msgDRO.getRedistributeId(), msgDRO.getBizType());
        log.info("向预警系统发送消息：tag:{},key:{},message:{}", MessageQueueTagConsts.ORDER_WORK_REDISTRIBUTE_TAG, key, JSON.toJSONString(msgDRO));
        zmnMQSender.send(performanceTopic, MessageQueueTagConsts.ORDER_WORK_REDISTRIBUTE_TAG, key, JSON.toJSONString(msgDRO));
    }
}
